﻿using System.Collections.Generic;
using System.Linq;

namespace EntityGraph.SQL
{
    internal partial class TypeTree
    {
        public SqlSelectColumns ToSql()
        {
            List<SqlColumnSelect> columns = new List<SqlColumnSelect>();
            var root = this.Root;
            foreach(var node in root)
            {
                foreach(var prop in node.Properties)
                {
                    columns.Add(new SqlColumnSelect("this_" + node.TypeId + "_", prop.Name, prop.Name + node.TypeId));
                }
            }
            SqlTable rootTable = new SqlTable(root.TableName, "this_" + root.TypeId + "_", root.EntityType.KeyMembers.First().Name);
            SqlTable table = rootTable;
            if(root.Count() > 1)
            {
                var nextNode = root.ElementAt(1);
                SqlTable nextTable = new SqlTable(nextNode.TableName, "this_" + nextNode.TypeId + "_", nextNode.EntityType.KeyMembers.First().Name);
                table = new SqlLeftOuterJoin(
                    rootTable,
                    nextTable,
                    new SqlEqualityExpression(
                        new SqlColumnExpression(new SqlColumn(rootTable.AsName, rootTable.Key)),
                        new SqlColumnExpression(new SqlColumn(nextTable.AsName, nextTable.Key))));
                foreach(var n in root.Skip(2))
                {
                    nextTable = new SqlTable(n.TableName, "this_" + n.TypeId + "_", n.EntityType.KeyMembers.First().Name);
                    table = new SqlLeftOuterJoin(
                        table,
                        nextTable,
                        new SqlEqualityExpression(
                            new SqlColumnExpression(new SqlColumn(rootTable.AsName, rootTable.Key)),
                            new SqlColumnExpression(new SqlColumn(nextTable.AsName, nextTable.Key))));
                }
            }
            List<SqlWhen> whens = new List<SqlWhen>();

            foreach(var node in root.Reverse().Where(n => n.EntityType.Abstract == false))
            {
                whens.Add(
                    new SqlWhen(new IsNotNull(new SqlColumnExpression(new SqlColumn("this_" + node.TypeId + "_", node.EntityType.KeyMembers.First().Name))),
                            new SqlConstantExpression(node.TypeId.ToString())));
            }
            columns.Add(new SqlCase("type_" + root.TypeId, whens));
            var select = new SqlSelectColumns(columns, table, null);
            return select;
        }
    }
}
